package com.ervanalb.cellradio.shared.communicator.packets;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.nio.ByteBuffer;

/**
 * A quantum of transmitted information in the CellRadio network. At a minimum,
 * contains four fields: number, channel, replyTo, and data. Each is a 4-byte
 * integer except for data, which is a one-byte type identifier followed by any
 * amount of data.
 * 
 * @author eric
 */
public class Packet {

	/**
	 * A unique sequence number.
	 */
	public int number;
	/**
	 * The channel (unique to each machine, zero before communication is set up)
	 */
	public int channel;
	/**
	 * The sequence number of the packet to which this is a reply, or 0 if this
	 * packet was unprompted
	 */
	public int replyTo;
	/**
	 * The payload of the packet
	 */
	public PacketData pd;

	/**
	 * The IP address associated with this packet. Not part of the packet.
	 */
	public InetAddress addr;

	public Packet(DatagramPacket p) {
		ByteBuffer bb = ByteBuffer.allocate(p.getLength());
		bb.put(p.getData(), p.getOffset(), p.getLength());
		bb.rewind();

		this.number = bb.getInt();
		this.channel = bb.getInt();
		this.replyTo = bb.getInt();
		this.pd = new PacketData(bb);

		this.addr = p.getAddress();
	}

	public Packet(int number, int machine, int replyTo, PacketData pd,
			InetAddress addr) {
		this.number = number;
		this.channel = machine;
		this.replyTo = replyTo;
		this.pd = pd;
		this.addr = addr;
	}

	public int size() {
		return 4 * 4 + pd.size();
	}

	public ByteBuffer render() {
		ByteBuffer bb = ByteBuffer.allocate(size());
		bb.putInt(number);
		bb.putInt(channel);
		bb.putInt(replyTo);
		bb.put(pd.render());
		bb.rewind();
		return bb;
	}

	public String toString() {
		if (pd != null) {
			switch (pd.type) {
			case PacketData.TYPE_ACK:
				return "ACK " + replyTo + ", machine=" + channel;
			case PacketData.TYPE_CONNECT:
				return "CONNECT, num=" + number;
			case PacketData.TYPE_CONNECTED:
				return "CONNECTED, num=" + number + ", replyto=" + replyTo;
			case PacketData.TYPE_HELLO:
				return "HELLO, num=" + number + ", machine=" + channel;
			default:
				return "PACKET num=" + number + ", machine=" + channel
						+ ", replyto=" + replyTo + ", data=" + pd;
			}
		}
		return "null";
	}
}
